/* Copyright 2024 Coremail
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { StringUtil } from '@ohos/base/src/main/ets/utils/StringUtil';
import type { MailAddress, MailItem } from '@ohos/mail-app';
import { AttachmentVData } from './viewdata/AttachmentVData';

export enum MailOperation {
  Reply,
  ReplyAll,
  Forward,
  Delete,
  ToggleNew,
  ToggleFlag,
  Move,
  Reedit,
  DownloadFiles
}

type ComposeMailData = {
  to: MailAddress[];
  cc: MailAddress[];
  bcc: MailAddress[];
  subject: string;
  html: string | null;
}

type ComposeMailAttachment = {
  inline: boolean;
  name: string;
  type: string;
  subType: string;
  id: string;
  encoding: string;
  size: number;
  index: number;
  localPath: string | null;
}

export class ComposeMailGenerater {
  from: MailAddress;
  to: MailAddress[];
  cc: MailAddress[];
  bcc: MailAddress[];
  subject: string;
  html: string | null;

  inlineImgs: AttachmentVData[] = [];
  attachments: AttachmentVData[] = [];

  operation: MailOperation;
  receiveDate: string | null;
  currentAccount: string;

  constructor(mail: MailItem, operation: MailOperation, account: string) {
    this.from = mail.from
    this.to = mail.to
    this.cc = mail.cc
    this.bcc = mail.bcc
    this.subject = mail.subject
    this.html = mail.html || mail.text
    this.inlineImgs = mail.inlineImages.map(item => {
      let att = new AttachmentVData()
      att.name = item.name
      att.type = item.type
      att.subType = item.subType
      att.id = item.id
      att.encoding = item.encoding
      att.size = item.size
      att.index = item.index
      att.localPath = item.localPath
      return att
    })
    this.attachments = mail.attachments.map(item => {
      let att = new AttachmentVData()
      att.name = item.name
      att.type = item.type
      att.subType = item.subType
      att.id = item.id
      att.encoding = item.encoding
      att.size = item.size
      att.index = item.index
      att.localPath = item.localPath
      return att
    })
    this.receiveDate = mail.date.toLocaleString()
    this.operation = operation
    this.currentAccount = account
  }

  getComposeMailData(): ComposeMailData {
    let composeFrom: MailAddress = {
      name: this.from.name,
      email: this.from.email
    }
    let composeTo: MailAddress[] = this.to.map(item => {
      return {
        name: item.name,
        email: item.email
      }
    })
    let composeCc: MailAddress[] = this.cc.map(item => {
      return {
        name: item.name,
        email: item.email
      }
    })
    let composeBcc: MailAddress[] = this.bcc.map(item => {
      return {
        name: item.name,
        email: item.email
      }
    })
    switch (this.operation) {
      case MailOperation.Reply:
      // 收件人：原邮件发件人
        return {
          to: [composeFrom],
          cc: [],
          bcc: [],
          subject: "Re: " + this.subject,
          html: this.getOriginalMessage(),
        }
      case MailOperation.ReplyAll:
      // 收件人：原邮件发件人
      //抄送：原邮件收件人+原邮件抄送人（发件人账号去重）
        let arr = this.to.concat(this.cc)
        let obj = {};
        let newCCArray = arr.filter(item => obj[item.email] ? false : (obj[item.email] = true));
        newCCArray = newCCArray.filter(item => (item.email != this.currentAccount));
        return {
          to: [composeFrom],
          cc: newCCArray,
          bcc: composeBcc,
          subject: "Re: " + this.subject,
          html: this.getOriginalMessage(),
        }
      case MailOperation.Forward:
        return {
          to: [],
          cc: [],
          bcc: [],
          subject: "Fw: " + this.subject,
          html: this.getOriginalMessage(),
        }
      case MailOperation.Reedit:
        return {
          to: composeTo,
          cc: composeCc,
          bcc: composeBcc,
          subject: this.subject,
          html: this.html,
        }
    }
  }

  getComposeAttachments(): ComposeMailAttachment[] {
    if (this.operation == MailOperation.Forward || this.operation == MailOperation.Reedit) {
      return this.attachments.map(item => {
        return {
          inline: false,
          name: item.name,
          type: item.type,
          subType: item.subType,
          id: item.id,
          encoding: item.encoding,
          size: item.size,
          index: item.index,
          localPath: item.localPath
        }
      })
    }
    return []
  }

  getComposeInlineImgs(): ComposeMailAttachment[] {
    return this.inlineImgs.map(item => {
      return {
        inline: true,
        name: item.name,
        type: item.type,
        subType: item.subType,
        id: StringUtil.getCid(item.id),
        encoding: item.encoding,
        size: item.size,
        index: item.index,
        localPath: item.localPath
      }
    })
  }


  getOriginalMessage(): string {
    let sb = [];
    // class=\"cm_quote_msg\">
    // style="font-size:12pt;font-family:'Microsoft YaHei', 微软雅黑, Arial, sans-serif;line-height:1.2;color:#000;text-align:left;padding-left:5px;margin-left:5px;border-left:#b6b6b6 2px solid;margin-right:0;"
    sb.push(`<BLOCKQUOTE id="mailblock"; style="font-size:12pt;line-height:1.2;color:#000;text-align:left;padding-left:5px;margin-left:5px;border-left:#b6b6b6 2px solid;margin-right:0;">`)
    sb.push("----- Original Message -----")
    sb.push("<BR>")
    sb.push(`<B>From</B>: ${this.getMailAddressStr(this.from)}<BR>`);

    if (this.to) {
      for (let i = 0; i < this.to.length; i++) {
        if (i == 0) {
          sb.push("<B>To</B>: ");
        }
        sb.push(this.getMailAddressStr(this.to[i]));
        if (i != this.to.length - 1) {
          sb.push(",")
        } else {
          sb.push("<BR>")
        }
      }
    }
    if (this.cc) {
      for (let i = 0; i < this.cc.length; i++) {
        if (i == 0) {
          sb.push("<B>Cc</B>: ");
        }
        sb.push(this.getMailAddressStr(this.cc[i]));
        if (i != this.cc.length - 1) {
          sb.push(",")
        } else {
          sb.push("<BR>")
        }
      }
    }
    sb.push("<B>Sent</B>: ")
    sb.push(this.receiveDate)
    sb.push("<BR>")

    if (this.subject) {
      sb.push("<B>Subject</B>: ")
      sb.push(this.subject)
      sb.push("<BR>")
    }
    sb.push("<BR>")
    sb.push(this.replaceImage(this.html, this.inlineImgs))
    sb.push("</BLOCKQUOTE>")
    // + html.backupContent + suffix;
    return sb.join("");
  }

  replaceImage(content: string, inlineFiles: Array<AttachmentVData>): string {
    if (!content || !inlineFiles) {
      return content;
    }
    content = content.replace(/<img.*?src=\"cid:(.*?)\"([^>]*)>/g, (s, cid: string, other) => {
      let model = inlineFiles.filter(item => (StringUtil.getCid(item.id) == cid));
      let path = model.length > 0 ? model[0].localPath : "";
      return `<img src="${"file://" + path}" ${other} >`;
    });
    return content;
  }

  getMailAddressStr(mailAddress: MailAddress): string {
    if (!mailAddress) {
      return ""
    }
    if (mailAddress.name && mailAddress.email) {
      return `"${mailAddress.name}" &lt;${mailAddress.email}&gt;`
    }
    return mailAddress.email;
  }
}